package com.tomtop.core.utils;

import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

/**
 * 
 * @author lenovo 方法介绍 n : 创建 a : 添加 cv : 判断是否存在 r : 删除 c : 清理 s : 大小 g : 取出 to
 *         : 转化为原型 each : 遍历 filter : 过滤 group : 分组 join : 数组拼装为字符串，调用toString
 *         list : 重写list的值，保持原有序列的顺序 sort : 排序
 * @param <T>
 */

public final class ListUtils<T> {

	@FunctionalInterface
	public static interface GroupIterable<V, K> {
		K accept(final V v);
	}

	@FunctionalInterface
	public static interface EachIterable<T> {
		void accept(final T t);
	}

	@FunctionalInterface
	public static interface FilterIterable<T> {
		boolean test(final T t);
	}

	@FunctionalInterface
	public static interface ListNewList<T, N> {
		N accept(T t);
	}

	@FunctionalInterface
	public static interface MaxOrMin<T, N extends Comparable<N>> {
		N accept(final T t);
	}

	@FunctionalInterface
	public static interface OrderBy<T, N extends Comparable<N>> {
		N accept(final T t);
	}

	private List<T> list = new LinkedList<>();

	private ListUtils() {
	}

	public final static <T> ListUtils<T> n(final Collection<T> collection) {
		return new ListUtils<T>().a(collection);
	}

	public final static <T> ListUtils<T> n() {
		return n(null);
	}

	public final ListUtils<T> a(final T t) {
		if (t != null)
			this.list.add(t);
		return this;
	}

	public final ListUtils<T> a(@SuppressWarnings("unchecked") final T... ts) {
		for (T t : ts) {
			this.list.add(t);
		}
		return this;
	}

	public final ListUtils<T> a(final Collection<T> ts) {
		if (ts != null)
			this.list.addAll(ts);
		return this;
	}

	public final boolean cv(final T t) {
		return this.list.contains(t);
	}

	public final int s() {
		return this.list.size();
	}

	public final T g(final int index) {
		return this.list.get(index);
	}

	public final ListUtils<T> r(final int... indexs) {
		for (int index : indexs) {
			this.list.remove(index);
		}
		return this;
	}

	public final ListUtils<T> r(final T t) {
		this.list.remove(t);
		return this;
	}

	public final ListUtils<T> r(@SuppressWarnings("unchecked") final T... ts) {
		for (T t : ts) {
			this.list.remove(t);
		}
		return this;
	}

	public final ListUtils<T> c() {
		this.list.clear();
		return this;
	}

	public final List<T> to() {
		return this.list;
	}

	public final ListUtils<T> each(final EachIterable<? super T> eachIterable) {
		Iterator<T> it = this.list.iterator();
		while (it.hasNext()) {
			T t = (T) it.next();
			eachIterable.accept(t);
		}
		return this;
	}

	public final <N extends Comparable<N>> ListUtils<T> order(final OrderBy<T, N> orderby) {
		this.list.sort((t1, t2) -> orderby.accept(t1).compareTo(orderby.accept(t2)));
		return this;
	}

	public final <N extends Comparable<N>> ListUtils<T> orderDesc(final OrderBy<T, N> orderby) {
		this.list.sort((t1, t2) -> -1 * orderby.accept(t1).compareTo(orderby.accept(t2)));
		return this;
	}

	public final <N extends Comparable<N>> T min(final MaxOrMin<? super T, N> maxOrMin) {
		return m(maxOrMin, -1);
	}

	public final <N extends Comparable<N>> T max(final MaxOrMin<? super T, N> maxOrMin) {
		return m(maxOrMin, 1);
	}

	private final <N extends Comparable<N>> T m(final MaxOrMin<? super T, N> maxOrMin, int status) {
		if (isEmpty(this.list))
			return null;
		T mcv = null;
		N mom = null;
		for (T t : list) {
			N cv = maxOrMin.accept(t);
			if (cv == null)
				continue;
			if (mcv == null) {
				mcv = t;
				mom = cv;
				continue;
			}
			if (cv.compareTo(mom) * status > 0) {
				mcv = t;
				mom = cv;
			}
		}
		return mcv;
	}

	public final ListUtils<T> filter(final FilterIterable<? super T> filter) {
		this.list.removeIf(t -> !filter.test(t));
		return this;
	}

	public final <N> ListUtils<N> list( final ListNewList<? super T, N> lnl) {
		ListUtils<N> lu = ListUtils.n();
		this.each(t -> {
			N n = lnl.accept(t);
			if (n != null)
				lu.a(n);
		});
		return lu;
	}

	public final <K> MapUtils<K, List<T>> group(final GroupIterable<? super T, K> groupIterable) {
		MapUtils<K, List<T>> relust = MapUtils.n();
		this.each(t -> {
			if (t == null)
				return;
			K key = groupIterable.accept(t);
			if (key == null)
				return;
			List<T> it = relust.ck(key) ? relust.g(key) : new LinkedList<>();
			it.add(t);
			relust.a(key, it);
		});
		return relust;
	}

	public final String join() {
		return this.join(null);
	}

	public final String join(final String seg) {
		if (list.size() == 0)
			return "";
		StringBuffer ret = new StringBuffer(list.get(0) + "");
		for (T t : list) {
			if (seg != null)
				ret.append(seg);
			ret.append(t);
		}
		return ret.toString();
	}

	public final static boolean isNotEmpty(final Collection<?>... collections) {
		for (Collection<?> collection : collections) {
			if (collection == null || collection.isEmpty())
				return false;
		}
		return true;
	}

	public final static boolean isEmpty(final Collection<?>... args) {
		return !isNotEmpty(args);
	}
}
